package org.ala.tiktools.sharddb.tx;

import java.util.List;
import java.util.concurrent.Callable;

/**
 * 分库事务
 *
 * @author ala
 * @date 2024-12-27 14:50
 */
public interface IShardTransaction {


    /**
     *  自动提交
     *  @param name 分布式事务名称
     *  @param shardKey 分库的key，会自动被指定到ThreadLocalLookupKey中
     *  @param run 预提交逻辑
     */
    void withTxAutoCommit(String name, String shardKey, Runnable run) throws Exception;
    /**
     *  自定提交
     *  @param name 分布式事务名称
     *  @param shardKey 分库的key，会自动被指定到ThreadLocalLookupKey中
     *  @param call 预提交逻辑
     */
    <T> T withTxAutoCommit(String name, String shardKey, Callable<T> call) throws Exception;

    /**
     *  同步2pc
     *  <p> 需要手动commit或rollback
     *  @param name 分布式事务名称
     *  @param shardKey 分库的key，会自动被指定到ThreadLocalLookupKey中
     *  @param run 预提交逻辑
     */
    void withTx2PCSync(String name, String shardKey, Runnable run) throws Exception;
    /**
     *  同步2pc
     *  <p> 需要手动commit或rollback
     *  @param name 分布式事务名称
     *  @param shardKey 分库的key，会自动被指定到ThreadLocalLookupKey中
     *  @param run 预提交逻辑
     */
    <T> T withTx2PCSync(String name, String shardKey, Callable<T> run) throws Exception;

    /**
     *  异步2pc
     *  <p> 需要手动commit或rollback
     *  @param name 分布式事务名称
     *  @param shardKey 分库的key，会自动被指定到 ThreadLocalLookupKey 中
     *  @param metadata 额外信息，补偿时会回传这些信息
     *  @param run 预提交逻辑
     */
    <T> void withTx2PCAsync(String name, String shardKey, Object metadata, Runnable run) throws Exception;


    /**
     *  提交
     *  @param compensation 事务补偿逻辑（手动commit时多个子事务是顺序commit的，不能保证每个子事务都commit成功。若后面的失败了，前面的要手动补偿）
     */
    <T> void commit(ICompensation compensation) throws Exception;
    /**
     *  回滚
     */
    void rollback(ICompensation compensation) throws Exception;


    /**
     *  事务补偿
     *  <p> 在withTx2PCAsync的commit中，可能有些子事务已经commit成功，此时只能走补偿
     */
    public static interface ICompensation {
        /**
         * 自行决定是把成功的撤销掉，还是把失败的最终一致掉
         * @param successes 成功的那一批
         * @param failes    失败的那一批
         */
        void doCompensation(List<TxResult> successes, List<TxResult> failes) throws InstantiationException, IllegalAccessException;
    }
    /**
     *  事务执行结果
     */
    public static class TxResult {
        /**
         *  事务名称（当初建事务的那个name）
         */
        protected String name;
        /**
         *  事务是否成功
         */
        protected boolean success;
        /**
         *  事务成功执行结果
         */
        protected Object result;
        /**
         *  事务失败异常
         */
        protected Exception e;
        /**
         *  当初建任务时给的metadata
         */
        protected Object metadata;

        public static TxResult build(String name, boolean success, Object result, Exception e) {
            TxResult r = new TxResult();
            r.name = name;
            r.success = success;
            r.result = result;
            r.e = e;
            return r;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public Object getResult() {
            return result;
        }

        public void setResult(Object result) {
            this.result = result;
        }

        public Exception getE() {
            return e;
        }

        public void setE(Exception e) {
            this.e = e;
        }

        public Object getMetadata() {
            return metadata;
        }

        public void setMetadata(Object metadata) {
            this.metadata = metadata;
        }

        public TxResult metadata(Object metadata) {
            setMetadata(metadata);
            return this;
        }
    }
}
